{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# PF Optimization: HRP vs Markowitz and Equal-Weighted"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports & Settings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:21.517022Z",
     "start_time": "2020-06-18T23:00:21.499095Z"
    }
   },
   "outputs": [],
   "source": [
    "from collections import defaultdict\n",
    "from time import time\n",
    "import warnings\n",
    "\n",
    "from pathlib import Path\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas_datareader.data as web\n",
    "from logbook import Logger, StderrHandler, INFO, WARNING\n",
    "\n",
    "from zipline import run_algorithm\n",
    "from zipline.api import (attach_pipeline, pipeline_output,\n",
    "                         date_rules, time_rules, record,\n",
    "                         schedule_function, commission, slippage,\n",
    "                         set_slippage, set_commission, set_max_leverage,\n",
    "                         order_target, order_target_percent,\n",
    "                         get_open_orders, cancel_order)\n",
    "from zipline.data import bundles\n",
    "from zipline.utils.run_algo import load_extensions\n",
    "from zipline.pipeline import Pipeline, CustomFactor\n",
    "from zipline.pipeline.data import Column, DataSet\n",
    "from zipline.pipeline.domain import US_EQUITIES\n",
    "from zipline.pipeline.filters import StaticAssets\n",
    "from zipline.pipeline.loaders import USEquityPricingLoader\n",
    "from zipline.pipeline.loaders.frame import DataFrameLoader\n",
    "from trading_calendars import get_calendar\n",
    "\n",
    "from pypfopt.efficient_frontier import EfficientFrontier\n",
    "from pypfopt.hierarchical_risk_parity import HRPOpt\n",
    "from pypfopt import risk_models\n",
    "from pypfopt import expected_returns\n",
    "\n",
    "import pyfolio as pf\n",
    "from pyfolio.plotting import plot_rolling_returns, plot_rolling_sharpe\n",
    "from pyfolio.timeseries import forecast_cone_bootstrap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:22.866389Z",
     "start_time": "2020-06-18T23:00:22.864145Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.set_style('darkgrid')\n",
    "warnings.filterwarnings('ignore')\n",
    "np.random.seed(42)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load zipline extensions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Only need this in notebook to find bundle."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:27.614305Z",
     "start_time": "2020-06-18T23:00:27.605889Z"
    }
   },
   "outputs": [],
   "source": [
    "load_extensions(default=True,\n",
    "                extensions=[],\n",
    "                strict=True,\n",
    "                environ=None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:27.787006Z",
     "start_time": "2020-06-18T23:00:27.779352Z"
    }
   },
   "outputs": [],
   "source": [
    "log_handler = StderrHandler(format_string='[{record.time:%Y-%m-%d %H:%M:%S.%f}]: ' +\n",
    "                            '{record.level_name}: {record.func_name}: {record.message}',\n",
    "                            level=WARNING)\n",
    "log_handler.push_application()\n",
    "log = Logger('Algorithm')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Algo Params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:28.336548Z",
     "start_time": "2020-06-18T23:00:28.329786Z"
    }
   },
   "outputs": [],
   "source": [
    "N_LONGS = 25\n",
    "MIN_POSITIONS = 20"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Quandl Wiki Bundel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:29.694098Z",
     "start_time": "2020-06-18T23:00:29.653641Z"
    }
   },
   "outputs": [],
   "source": [
    "bundle_data = bundles.load('quandl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ML Predictions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:15.940032Z",
     "start_time": "2020-06-18T23:00:15.935787Z"
    }
   },
   "outputs": [],
   "source": [
    "def load_predictions(bundle):\n",
    "    path = Path('../../12_gradient_boosting_machines/data')\n",
    "    predictions = (pd.read_hdf(path / 'predictions.h5', 'lgb/train/01')\n",
    "                   .append(pd.read_hdf(path / 'predictions.h5', 'lgb/test/01').drop('y_test', axis=1)))\n",
    "    predictions = (predictions.loc[~predictions.index.duplicated()]\n",
    "                   .iloc[:, :10]\n",
    "                   .mean(1)\n",
    "                   .sort_index()\n",
    "                   .dropna()\n",
    "                  .to_frame('prediction'))\n",
    "    tickers = predictions.index.get_level_values('symbol').unique().tolist()\n",
    "\n",
    "    assets = bundle.asset_finder.lookup_symbols(tickers, as_of_date=None)\n",
    "    predicted_sids = pd.Int64Index([asset.sid for asset in assets])\n",
    "    ticker_map = dict(zip(tickers, predicted_sids))\n",
    "\n",
    "    return (predictions\n",
    "            .unstack('symbol')\n",
    "            .rename(columns=ticker_map)\n",
    "            .prediction\n",
    "            .tz_localize('UTC')), assets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.075335Z",
     "start_time": "2020-06-18T23:00:15.941129Z"
    }
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "File ../../12_gradient_boosting_machines/data/predictions.h5 does not exist",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-8-538a92167a3a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mpredictions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0massets\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mload_predictions\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbundle_data\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-7-013836ed2eb6>\u001b[0m in \u001b[0;36mload_predictions\u001b[0;34m(bundle)\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mload_predictions\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbundle\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m     \u001b[0mpath\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mPath\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../../12_gradient_boosting_machines/data'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m     predictions = (pd.read_hdf(path / 'predictions.h5', 'lgb/train/01')\n\u001b[0m\u001b[1;32m      4\u001b[0m                    .append(pd.read_hdf(path / 'predictions.h5', 'lgb/test/01').drop('y_test', axis=1)))\n\u001b[1;32m      5\u001b[0m     predictions = (predictions.loc[~predictions.index.duplicated()]\n",
      "\u001b[0;32m~/.pyenv/versions/miniconda3-latest/envs/ml4t-zipline/lib/python3.5/site-packages/pandas/io/pytables.py\u001b[0m in \u001b[0;36mread_hdf\u001b[0;34m(path_or_buf, key, mode, **kwargs)\u001b[0m\n\u001b[1;32m    345\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mexists\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    346\u001b[0m             raise compat.FileNotFoundError(\n\u001b[0;32m--> 347\u001b[0;31m                 'File %s does not exist' % path_or_buf)\n\u001b[0m\u001b[1;32m    348\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    349\u001b[0m         \u001b[0mstore\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHDFStore\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mpath_or_buf\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmode\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFileNotFoundError\u001b[0m: File ../../12_gradient_boosting_machines/data/predictions.h5 does not exist"
     ]
    }
   ],
   "source": [
    "predictions, assets = load_predictions(bundle_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.077886Z",
     "start_time": "2020-06-18T23:00:14.738Z"
    }
   },
   "outputs": [],
   "source": [
    "predictions.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define Custom Dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.079033Z",
     "start_time": "2020-06-18T23:00:14.747Z"
    }
   },
   "outputs": [],
   "source": [
    "class SignalData(DataSet):\n",
    "    predictions = Column(dtype=float)\n",
    "    domain = US_EQUITIES"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define Pipeline Loaders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.080000Z",
     "start_time": "2020-06-18T23:00:14.751Z"
    }
   },
   "outputs": [],
   "source": [
    "signal_loader = {SignalData.predictions:\n",
    "                     DataFrameLoader(SignalData.predictions, predictions)}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Pipeline Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Custom ML Factor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.081123Z",
     "start_time": "2020-06-18T23:00:14.756Z"
    }
   },
   "outputs": [],
   "source": [
    "class MLSignal(CustomFactor):\n",
    "    \"\"\"Converting signals to Factor\n",
    "        so we can rank and filter in Pipeline\"\"\"\n",
    "    inputs = [SignalData.predictions]\n",
    "    window_length = 1\n",
    "\n",
    "    def compute(self, today, assets, out, predictions):\n",
    "        out[:] = predictions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create Pipeline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.082227Z",
     "start_time": "2020-06-18T23:00:14.760Z"
    }
   },
   "outputs": [],
   "source": [
    "def compute_signals():\n",
    "    signals = MLSignal()\n",
    "    return Pipeline(columns={\n",
    "        'longs' : signals.top(N_LONGS, mask=signals > 0)\n",
    "    },\n",
    "            screen=StaticAssets(assets))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize Algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.083400Z",
     "start_time": "2020-06-18T23:00:14.765Z"
    }
   },
   "outputs": [],
   "source": [
    "def initialize(context):\n",
    "    \"\"\"\n",
    "    Called once at the start of the algorithm.\n",
    "    \"\"\"\n",
    "    context.n_longs = N_LONGS\n",
    "    context.min_positions = MIN_POSITIONS\n",
    "    context.universe = assets\n",
    "    context.trades = pd.Series()\n",
    "    context.longs = 0\n",
    "    \n",
    "    set_slippage(slippage.FixedSlippage(spread=0.00))\n",
    "    set_commission(commission.PerShare(cost=0.001, min_trade_cost=1))\n",
    "\n",
    "    schedule_function(rebalance_markowitz,\n",
    "                      date_rules.every_day(),\n",
    "#                       date_rules.week_start(),\n",
    "                      time_rules.market_open(hours=1, minutes=30))\n",
    "\n",
    "    schedule_function(record_vars,\n",
    "                      date_rules.every_day(),\n",
    "                      time_rules.market_close())\n",
    "\n",
    "    pipeline = compute_signals()\n",
    "    attach_pipeline(pipeline, 'signals')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Get daily Pipeline results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.084498Z",
     "start_time": "2020-06-18T23:00:14.769Z"
    }
   },
   "outputs": [],
   "source": [
    "def before_trading_start(context, data):\n",
    "    \"\"\"\n",
    "    Called every day before market open.\n",
    "    \"\"\"\n",
    "    output = pipeline_output('signals')['longs'].astype(int)\n",
    "    context.longs = output[output!=0].index\n",
    "    if len(context.longs) < MIN_POSITIONS:\n",
    "        context.divest = set(context.portfolio.positions.keys())\n",
    "    else:\n",
    "        context.divest = context.portfolio.positions.keys() - context.longs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Define Rebalancing Logic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.085606Z",
     "start_time": "2020-06-18T23:00:14.773Z"
    }
   },
   "outputs": [],
   "source": [
    "def optimize_weights(prices, short=False):\n",
    "    returns = expected_returns.mean_historical_return(prices=prices, \n",
    "                                                      frequency=252)\n",
    "    cov = risk_models.sample_cov(prices=prices, frequency=252)\n",
    "\n",
    "    # get weights that maximize the Sharpe ratio\n",
    "    ef = EfficientFrontier(expected_returns=returns, \n",
    "                           cov_matrix=cov, \n",
    "                           weight_bounds=(0, 1), \n",
    "                           gamma=0)\n",
    "    \n",
    "    weights = ef.max_sharpe()\n",
    "    if short:\n",
    "        return {asset: -weight for asset, weight in ef.clean_weights().items()}\n",
    "    else:\n",
    "        return ef.clean_weights()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.086661Z",
     "start_time": "2020-06-18T23:00:14.776Z"
    }
   },
   "outputs": [],
   "source": [
    "def rebalance_equal_weighted(context, data):\n",
    "    \"\"\"\n",
    "    Execute orders according to schedule_function() date & time rules.\n",
    "    \"\"\"\n",
    "    for symbol, open_orders in get_open_orders().items():\n",
    "        for open_order in open_orders:\n",
    "            cancel_order(open_order)\n",
    "      \n",
    "    for asset in context.divest:\n",
    "        order_target(asset, target=0)\n",
    "        \n",
    "    if len(context.longs) > context.min_positions:\n",
    "        for asset in context.longs:\n",
    "            order_target_percent(asset, 1/len(context.longs))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.087812Z",
     "start_time": "2020-06-18T23:00:14.782Z"
    }
   },
   "outputs": [],
   "source": [
    "def rebalance_markowitz(context, data):\n",
    "    \"\"\"\n",
    "    Execute orders according to schedule_function() date & time rules.\n",
    "    \"\"\"\n",
    "    for symbol, open_orders in get_open_orders().items():\n",
    "        for open_order in open_orders:\n",
    "            cancel_order(open_order)\n",
    "      \n",
    "    for asset in context.divest:\n",
    "        order_target(asset, target=0)\n",
    "        \n",
    "    if len(context.longs) > context.min_positions:\n",
    "        prices = data.history(context.longs, fields='price',\n",
    "                          bar_count=252+1, # for 1 year of returns \n",
    "                          frequency='1d')\n",
    "        markowitz_weights = optimize_weights(prices)\n",
    "        for asset, target in markowitz_weights.items():\n",
    "            order_target_percent(asset=asset, target=target)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.089079Z",
     "start_time": "2020-06-18T23:00:14.787Z"
    }
   },
   "outputs": [],
   "source": [
    "def rebalance_hierarchical_risk_parity(context, data):\n",
    "    \"\"\"\n",
    "    Execute orders according to schedule_function() date & time rules.\n",
    "    \"\"\"\n",
    "    for symbol, open_orders in get_open_orders().items():\n",
    "        for open_order in open_orders:\n",
    "            cancel_order(open_order)\n",
    "      \n",
    "    for asset in context.divest:\n",
    "        order_target(asset, target=0)\n",
    "        \n",
    "    if len(context.longs) > context.min_positions:\n",
    "        returns = (data.history(context.longs, fields='price',\n",
    "                          bar_count=252+1, # for 1 year of returns \n",
    "                          frequency='1d')\n",
    "                   .pct_change()\n",
    "                   .dropna(how='all'))\n",
    "        hrp_weights = HRPOpt(returns=returns).hrp_portfolio()\n",
    "        for asset, target in hrp_weights.items():\n",
    "            order_target_percent(asset=asset, target=target)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Record Data Points"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.090318Z",
     "start_time": "2020-06-18T23:00:14.792Z"
    }
   },
   "outputs": [],
   "source": [
    "def record_vars(context, data):\n",
    "    \"\"\"\n",
    "    Plot variables at the end of each day.\n",
    "    \"\"\"\n",
    "    record(leverage=context.account.leverage,\n",
    "           longs=context.longs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run Algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.091567Z",
     "start_time": "2020-06-18T23:00:14.796Z"
    }
   },
   "outputs": [],
   "source": [
    "dates = predictions.index.get_level_values('date')\n",
    "start_date, end_date = dates.min(), dates.max()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.092629Z",
     "start_time": "2020-06-18T23:00:14.800Z"
    }
   },
   "outputs": [],
   "source": [
    "print('Start: {}\\nEnd:   {}'.format(start_date.date(), end_date.date()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.093676Z",
     "start_time": "2020-06-18T23:00:14.804Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "start = time()\n",
    "results = run_algorithm(start=start_date,\n",
    "                        end=end_date,\n",
    "                        initialize=initialize,\n",
    "                        before_trading_start=before_trading_start,\n",
    "                        capital_base=1e5,\n",
    "                        data_frequency='daily',\n",
    "                        bundle='quandl',\n",
    "                        custom_loader=signal_loader)  # need to modify zipline\n",
    "\n",
    "print('Duration: {:.2f}s'.format(time() - start))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## PyFolio Analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.095048Z",
     "start_time": "2020-06-18T23:00:14.808Z"
    }
   },
   "outputs": [],
   "source": [
    "returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(results)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.096450Z",
     "start_time": "2020-06-18T23:00:14.812Z"
    }
   },
   "outputs": [],
   "source": [
    "experiment = 'markowitz'\n",
    "with pd.HDFStore('backtests.h5') as store:\n",
    "    store.put('returns/{}'.format(experiment), returns)\n",
    "    store.put('positions/{}'.format(experiment), positions)\n",
    "    store.put('transactions/{}'.format(experiment), transactions)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.097827Z",
     "start_time": "2020-06-18T23:00:14.815Z"
    }
   },
   "outputs": [],
   "source": [
    "experiment = 'hrp'\n",
    "with pd.HDFStore('backtests.h5') as store:\n",
    "    returns = store.get('returns/{}'.format(experiment))\n",
    "    positions = store.get('positions/{}'.format(experiment))\n",
    "    transactions = store.get('transactions/{}'.format(experiment))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.099039Z",
     "start_time": "2020-06-18T23:00:14.819Z"
    }
   },
   "outputs": [],
   "source": [
    "benchmark = web.DataReader('SP500', 'fred', '2014', '2018').squeeze()\n",
    "benchmark = benchmark.pct_change().tz_localize('UTC')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Custom Plots"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.100160Z",
     "start_time": "2020-06-18T23:00:14.823Z"
    }
   },
   "outputs": [],
   "source": [
    "fig, axes = plt.subplots(ncols=3, nrows=2, figsize=(18, 8))\n",
    "exp_dict = {'ew': 'Equal Weighted', 'hrp': 'Hierarchical Risk Parity', 'markowitz': 'Markowitz (MFT)'}\n",
    "for i, experiment in enumerate(['ew', 'hrp', 'markowitz']):\n",
    "    returns = pd.read_hdf('backtests.h5', 'returns/{}'.format(experiment))    \n",
    "    plot_rolling_returns(returns,\n",
    "                         factor_returns=benchmark,\n",
    "                         live_start_date='2017-01-01',\n",
    "                         logy=False,\n",
    "                         cone_std=2,\n",
    "                         legend_loc='best',\n",
    "                         volatility_match=False,\n",
    "                         cone_function=forecast_cone_bootstrap,\n",
    "                        ax=axes[0][i])\n",
    "    plot_rolling_sharpe(returns, ax=axes[1][i], rolling_window=63)\n",
    "    axes[0][i].set_title('{} | Cumulative Returns'.format(exp_dict[experiment]))\n",
    "    axes[1][i].set_title('{} | Rolling Sharpe Ratio'.format(exp_dict[experiment]))\n",
    "    fig.tight_layout()\n",
    "    fig.savefig('../figures/pf_optimization', dpi=300);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Tear Sheets"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Equal Weighted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.101227Z",
     "start_time": "2020-06-18T23:00:14.885Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "experiment = 'ew'\n",
    "with pd.HDFStore('backtests.h5') as store:\n",
    "    returns = store.get('returns/{}'.format(experiment))\n",
    "    positions = store.get('positions/{}'.format(experiment))\n",
    "    transactions = store.get('transactions/{}'.format(experiment))\n",
    "\n",
    "pf.create_full_tear_sheet(returns, \n",
    "                          positions=positions, \n",
    "                          transactions=transactions,\n",
    "                          benchmark_rets=benchmark,\n",
    "                          live_start_date='2017-01-01', \n",
    "                          round_trips=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### HRP"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.102276Z",
     "start_time": "2020-06-18T23:00:14.959Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "experiment = 'hrp'\n",
    "with pd.HDFStore('backtests.h5') as store:\n",
    "    returns = store.get('returns/{}'.format(experiment))\n",
    "    positions = store.get('positions/{}'.format(experiment))\n",
    "    transactions = store.get('transactions/{}'.format(experiment))\n",
    "\n",
    "pf.create_full_tear_sheet(returns, \n",
    "                          positions=positions, \n",
    "                          transactions=transactions,\n",
    "                          benchmark_rets=benchmark,\n",
    "                          live_start_date='2017-01-01', \n",
    "                          round_trips=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Markowitz"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-18T23:00:16.103363Z",
     "start_time": "2020-06-18T23:00:14.987Z"
    },
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "experiment = 'markowitz'\n",
    "with pd.HDFStore('backtests.h5') as store:\n",
    "    returns = store.get('returns/{}'.format(experiment))\n",
    "    positions = store.get('positions/{}'.format(experiment))\n",
    "    transactions = store.get('transactions/{}'.format(experiment))\n",
    "\n",
    "pf.create_full_tear_sheet(returns, \n",
    "                          positions=positions, \n",
    "                          transactions=transactions,\n",
    "                          benchmark_rets=benchmark,\n",
    "                          live_start_date='2017-01-01', \n",
    "                          round_trips=True)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:ml4t-zipline]",
   "language": "python",
   "name": "conda-env-ml4t-zipline-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.6"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
